<?php

namespace App\Exceptions;

use App\Kuafu\Base\Enum\BaseCodeEnum;
use App\Kuafu\User\Enum\UserCodeEnum;
use App\Library\FeiShu\SendFs;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\Exceptions\ThrottleRequestsException;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;
use Throwable;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'current_password',
        'password',
        'password_confirmation',
    ];

    /**
     * Register the exception handling callbacks for the application.
     *
     * @return void
     */
    public function register()
    {
        $this->reportable(function (Throwable $e) {
            // 飞书机器人报错推送

            // 推送代码默认报错 || 手动设置了previous的报错
            if ($e->getCode() == 0 || $e->getPrevious()) {
                self::sendFSReport($e);
            }
        });
    }

    /**
     * Report or log an exception.
     *
     * @param \Throwable $exception
     * @return void
     *
     * @throws \Throwable
     */
    public function report(Throwable $exception)
    {
        array_push($this->internalDontReport, CustomValidateException::class);
        parent::report($exception);
    }


    /**
     * Render an exception into an HTTP response.
     *
     * @param \Illuminate\Http\Request $request
     * @param Throwable $exception
     * @return \Illuminate\Http\JsonResponse|\Illuminate\Http\Response|\Symfony\Component\HttpFoundation\Response
     *
     * @throws Throwable
     */
    public function render($request, Throwable $exception)
    {
        if ($exception instanceof BaseException) {
            // 如果是自定义的异常
            $this->code    = $exception->code;
            $this->message = $exception->message;
        } elseif ($exception instanceof ValidationException) {

            $msg = '';
            foreach ($exception->errors() as $v) {
                $msg .= implode('; ', $v) . '; ';
            }

            // validate
            $this->code    = 422;
            $this->message = $msg ?: $exception->getMessage();
        } elseif ($exception instanceof ThrottleRequestsException) {
            // validate
            $this->code    = $exception->getStatusCode();
            $this->message = "操作频繁，请稍后再试！";
        } else {
            // 定义异常开关
            if (config('app.debug')) {
                return parent::render($request, $exception);
            }

            $this->code    = 0;
            $this->message = '服务器内部错误';
            // TODO 记录日志 和 消息通知（邮件短信等）
        }

        $result = [
            'code' => $this->code,
            'msg'  => $this->message,
            'data' => null
        ];

        // 显示中文
        return response()->json($result)->setEncodingOptions(JSON_UNESCAPED_UNICODE);
    }

    /**
     * Send FS Report
     *
     * @param $exception
     */
    private static function sendFSReport($exception)
    {
        // 报错信息完善内容
        $error_message_func = function () use ($exception) {
            $baseMessage = $exception->getMessage();

            if ($exception->getPrevious()) {
                $baseMessage .= PHP_EOL . "-----" . PHP_EOL . $exception->getPrevious()->getMessage();
            }

            return $baseMessage;
        };

        $message = "[" . config('app.name') . "] の【" . config('app.env') . "】 环境出错啦 : \n\n\r";

        $request_url    = \request()->getUri();
        $request_method = request()->method();
        $request_params = json_encode(\request()->all());
        $request_header = json_encode(\request()->header());
        $server_ip      = $_SERVER['SERVER_ADDR'] ?? '0.0.0.0';
        $error_line     = $exception->getLine();
        $error_message  = $error_message_func();
        $error_file     = $exception->getFile();

        $data = compact(
            'request_method',
            'request_url',
            'error_message',
            'request_params',
            'request_header',
            'server_ip',
            'error_line',
            'error_file'
        );

        foreach ($data as $key => $datum) {
            $arr     = explode('_', $key);
            $message .= "[";
            foreach ($arr as $item) {
                $message .= trans('messages.' . $item);
            }
            $message .= "]：\n" . $datum . "\n\n";
        }

        // 需要单独推送的错误码
        $fsRobot = SendFs::ROBOT_WARNING;
        if (in_array($exception->getCode(), [BaseCodeEnum::ERR_TOKEN_ERROR])) {
            $fsRobot = SendFs::ROBOT_BUSINESS_WARING;
        }

        // 机器人错误提醒
        try {
            if ('dev' != config('app.env')) {
                SendFs::newRobot($fsRobot)->setTitleContent('报错信息推送', $message)->send();
            }

        } catch (\Exception $e) {
        }
    }
}
